"""Wrapper for database queries."""

__author__  =  'Tailgunner'
__project__ =  'MW:O Drop Planner'

import logging

from google.appengine.ext        import db
from google.appengine.api        import memcache

from lib.model.Mech import Mech
from lib.Toolbox    import WebTools

import datetime
from datetime import date
from datetime import datetime


logging.getLogger().setLevel(logging.DEBUG)

class Mechs():
    
    cache = {}
     
    @classmethod
    def mech_by_dropid_and_player(cls, dropid, player, mechlist=None, cached=True):
        """Returns the mech a player uses in a drop."""
        
        if mechlist == None:
            cls.mechs_by_dropid(dropid, cached=cached)
            
        uplayer = WebTools.utf8_ify(player)
        logging.info("mech_by_dropid_and_player: %s / %s", dropid, player)
        for mech in mechlist:
            logging.info("mech_by_dropid_and_player: is it %s / %s", mech.player, uplayer)
            if mech.player == uplayer:
                logging.info("mech_by_dropid_and_player: found mech")
                return mech
        
        return None    
    
    @classmethod        
    def mechs_by_dropid(cls, dropid, order="lance", cached=True):
        """Returns a list of mechs per Drop-ID."""
        
        # try to fetch from cache unless prohibited
        if cached:
            try:
                
                mechlist = cls.get_from_cache(dropid)
                
                if mechlist is not None:
                    logging.info("mechs_by_dropid: return cached list %s, ", mechlist)
                    return mechlist
            except:
                pass

        # Nothing in cache or cache error,
        # fetch from database
        mechlist = []
        
        qtext = "SELECT * FROM Mech WHERE dropid = :1 and name=''"
        
        if order != "":
            qtext = qtext + " ORDER BY " + order
               
        query = db.GqlQuery(qtext, dropid)
        
        for i in query:
            logging.info("mechs_by_dropid: found mech of %s", i.player)
            mechlist.append(i)
 

        # Put the result in the cache for five minutes
        try:
            cls.put_in_cache(dropid, mechlist, 5 * 60, "mechlist:mechs_by_dropid")
        except:
            pass
        
        logging.info("mechs_by_dropid: return fetched list")
        return mechlist
    
    @classmethod
    def mechs_by_player(cls, player, order="", cached=True):
        """Returns a list of mechs per player."""
        
        # try to fetch from cache unless prohibited
        #if cached:
        #    try:
        #        list = cls.get_from_cache("P_" + player)
        #  
        #        if list is not None:
        #            return list
        #    except:
        #        pass
        
        # Nothing in cache or cache error,
        # fetch from database
        list = []
        
        try:
            qtext = 'SELECT * FROM Mech WHERE player = :1'
            
            if order == "weight":
                query = db.GqlQuery(qtext, WebTools.utf8_ify(player))
    
                for i in query:
                    list.append(i)
                    
                list = sorted( list, key=lambda x: x.weight() ) 
            else:
                if order != "":
                    qtext = qtext + " ORDER BY " + order
                    
                query = db.GqlQuery(qtext, WebTools.utf8_ify(player))
    
                for i in query:
                    list.append(i)
        except:
            pass
        
        # Put the result in the cache for five minutes
        #try:
        #    cls.put_in_cache("P_" + player, list, 5 * 60)
        #except:
        #    pass

        return list
    
    @classmethod
    def named_mechs_by_player(cls, player, order="", cached=True):
        """Returns a list of named mechs per player (the players 'garage')."""
            
        mechs = cls.mechs_by_player(player, order, cached)
        list = []

        for m in mechs:
            if m.name != "":
                list.append(m)
                
        return list
    
    @classmethod
    def mech_by_player_and_name(cls, player, name, mechlist=None, cached=True):
        """Returns a mech with a specific name from a players garage."""
        
        mechs    = cls.mechs_by_player(player, cached=cached)
        uplayer  = WebTools.utf8_ify(player)
        uname    = WebTools.utf8_ify(name)

        for mech in mechs:
            logging.info("mech_by_player_and_name: " + mech.name + "==" + uname + " : " + mech.player + " == " + uplayer)
            if mech.name == uname and mech.player == uplayer:
                logging.info("mech_by_player_and_name: found " + mech.name + "/" + mech.player)
                return mech
            
        return None
    
    @classmethod
    def drop_leader(cls, dropid, mechlist=None, cached=True):
        """Returns the name of the leader of a drop."""
        
        if not mechlist:
            mechlist = cls.mechs_by_dropid(dropid, cached=cached)
        
        for mech in mechlist:
            if mech.starter == 1:
                return mech.player

        return ""
    
    @classmethod
    def number_of_mechs_per_drop(cls, dropid):
        mechlist = cls.mechs_by_dropid(dropid)
        return len(mechlist)

    @classmethod
    def add_mech(cls, dropid, speed, mechtype, name, position, player, modules, weapons, args):
        
        logging.info("add_mech: player: %s name: '%s'", player, name)
        logging.info("add_mech: mechlist BEFORE add: %s", len(args['mechlist']))
        
        mech = None
      
        try:
            mech = Mech(
                dropid=dropid, speed=int(speed), mechtype=mechtype, name=WebTools.utf8_ify(name),
                player=WebTools.utf8_ify( player), position = position, 
                lance = "Reserve", weapons = weapons, modules = modules
            )
        
            if len(args['mechlist']) == 0:
                mech.starter = 1;
                
            logging.info("add_mech: writing")
            mech.put()
            logging.info("add_mech: written")
            
            if name == "":
                args['mechlist'].append(mech)
                logging.info("add_mech: mechlist AFTER add: %s", len(args['mechlist']))
                
                logging.info("add_mech: caching")
                cls.put_in_cache(dropid, args['mechlist'], 5 * 60 * 60, "add_mech")
        except:
            mech = None
        
        
        
        return mech
    
    #
    # Save changes to an existing mech 
    #
    @classmethod
    def save_mech(cls, dropid, speed, mechtype, name, position, player, modules, weapons, args):
        uplayer = WebTools.utf8_ify(player)
        m       = cls.find_mech(dropid, name, player, args)
        
        if m:
            mech_changed = 0
    
            logging.info("save_mech: utf8ify: %s / %s / %s" , m.player, player, uplayer)
                    
            try:
                speed = int(speed)
                if m.speed != speed: 
                    mech_changed = 1
                    
                m.speed = speed
            except:
                pass
            
            if m.mechtype != mechtype: 
                mech_changed = 1
    
            m.mechtype = mechtype
    
            if position != "":
                if m.position != position: 
                    mech_changed = 1
                    
                m.position = position
                
            
            if len(m.weapons) != len(weapons): 
                mech_changed = 1
                
            m.weapons = weapons
            
            if len(m.modules) != len(modules): 
                mech_changed = 1
                
            m.modules = modules
         
            if mech_changed:
                logging.info("save_mech: writing " + str(m.starter) + " * ")
                m.put()
                cls.put_in_cache(dropid, args['mechlist'], 5 * 60 * 60, "save_mech")
            else:
                logging.info("save_mech: no changes")
    
        return m
       
    @classmethod 
    def find_mech(cls, dropid, name, player, args):
        m = None
        
        if name != "":
            logging.info("find_mech_by_player_and_name: player: %s name: %s", player, name)
            m = cls.mech_by_player_and_name(player, name, cached=False)
        else:
            logging.info("find_mech_by_dropid_and_player: player: %s", player)
            m = cls.mech_by_dropid_and_player(dropid, player, mechlist=args['mechlist'], cached=False)
            
        return m
        
    @classmethod
    def invalidate_cache(cls, key):
        try:
            logging.info("invalidate_cache: key: %s", key)
            memcache.delete(key)
            cls.cache.pop(key)
        except:
            pass
        
       

    @classmethod
    def get_from_cache(cls, key):
        try:
            logging.info("get_from_cache: key: %s", key)
            if not key in cls.cache:
                logging.info("get_from_cache: mechcache: key: %s", key)
                cls.cache[key] = memcache.get(key)
                
            if key in cls.cache:
                logging.info("get_from_cache: found key: %s", key)
                return cls.cache[key]
            else:
                logging.info("get_from_cache: not found key: %s", key)
                return None
        except:
            return None
        
        
    
    @classmethod
    def put_in_cache(cls, key, value, ttl, caller=""):
        logging.info("put_in_cache: D" + key + ": %s caller: %s", key, datetime.now())
        memcache.set("D"+key, datetime.now().isoformat(), ttl)
        try:
            logging.info("put_in_cache: key: %s caller: %s", key, caller)
            memcache.set(key, value, ttl)
            
           
            cls.cache[key] = value
            
            return True
        except:
            return False
        
    @classmethod
    def set_dropleader(cls, dropid, player, mechlist=None):
        logging.info("set_dropleader: player: %s ", player)
        
        if not mechlist:
            mechlist=cls.mechs_by_dropid(dropid)
        
        mchange = False
        lchange = False
        
        for m in mechlist:
            mchange = False
            
            if m.player == WebTools.utf8_ify(player):
                logging.info("set_dropleader: is starter: %s mplayer %s", player, m.player)
                if m.starter == 0:
                    mchange = True
                    
                m.starter = 1
            else:
                if m.starter == 1:
                    mchange = True
                    
                logging.info("set_dropleader: not starter: %s mplayer %s", player, m.player)
                m.starter = 0
    
            if mchange:
                lchange = True
                m.put()
                logging.info("set_dropleader: starter: %s", m.starter)
            
        if lchange:
            cls.put_in_cache(dropid, mechlist, 5 * 60, "set_dropleader: caching mechlist:")
        
            
        return m
            
            
    @classmethod
    def remove_player(cls, dropid, players, mechlist=None):
        deleted = []
        
        if not mechlist:
            mechlist=cls.mechs_by_dropid(dropid)
        
        for p in players:
            for m in mechlist:
                if m.player == p:
                    deleted.append(m.player)
                    m.delete()
        
        if len(deleted) > 0:
            for d in deleted:
                for m in mechlist:
                    if d == m.player:
                        mechlist.remove(m)
                        
            cls.put_in_cache(dropid, mechlist, 5 * 60, "assign_lance: caching mechlist:")
                
    @classmethod
    def assign_lance(cls, dropid, players, lance, mechlist=None):
        if lance != "":
            
            if not mechlist:
                mechlist=cls.mechs_by_dropid(dropid)
            
            logging.info("lance: " + lance)
 
            for m in mechlist:
                for p in players:
                    logging.info("lance: %s chekci: %s, %s", lance, p, m.player)
                    if m.player == p:
                        logging.info("assigning: " + lance)
                        m.lance = lance
                        m.put()
                        
                        cls.put_in_cache(dropid, mechlist, 5 * 60, "assign_lance: caching mechlist:")
            


            
